#include "EventLoop.h"

//创建定时器fd
int createTimerfd(int sec = 30)
{
    int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);  //创建timerfd
    struct itimerspec timeout;      //定时器时间的数据结构
    memset(&timeout, 0, sizeof(struct itimerspec));
    timeout.it_value.tv_sec = sec;    //定时时间
    timeout.it_value.tv_nsec = 0;
    timerfd_settime(tfd, 0, &timeout, 0);
    return tfd;
}

//构造函数中创建Epoll对象ep_(创建一个epoll)
EventLoop::EventLoop(bool isMainloop, int timetvl, int timeout)
:ep_(new Epoll),wakeupfd_(eventfd(0, EFD_NONBLOCK)),wakeChannel_(new Channel(this, wakeupfd_)), 
stop_(false),timetvl_(timetvl), timeout_(timeout), timerfd_(createTimerfd(timeout_)),timeChannel_(new Channel(this, timerfd_)),mainloop_(isMainloop)
{
    wakeChannel_->set_Read_CallBack(std::bind(&EventLoop::handleWakeUp, this));
    wakeChannel_->enable_Reading();

    timeChannel_->set_Read_CallBack(std::bind(&EventLoop::handleTimer, this));
    timeChannel_->enable_Reading();
}
//析构函数中销毁ep_
EventLoop::~EventLoop()
{
    // delete ep_;
}

//停止事件循环
void EventLoop::stop()    
{
    stop_ = true;
    wakeUp();    //唤醒事件循环，让事件循环脱离wait()，否则需要等到闹钟到了或者超时才会脱离阻塞
}    

//运行事件循环
void EventLoop::run()
{
    threadID_ = syscall(SYS_gettid);    //获取事件循环线程所在的ID
    //printf("EventLoop::run() thread is %ld.\n", syscall(SYS_gettid));
    while(!stop_)
    {
        std::vector<Channel*> channels = ep_->loop(10 * 1000);       //存放epoll_wait()返回事件
        //如果channels为空，表示超时，回调TcpServer::epolltimeout()
        if(channels.size() == 0)
        {
            epoll_TimeOut_CallBack_(this);
        }
        else
        {
            //有事件
            for(auto &ch : channels)//遍历
            {
                ch->handle_Event();
            } 
        }
    }
}

Epoll *EventLoop::ep()
{
    return ep_.get();
}

void EventLoop::set_epoll_TimeOut_CallBack(std::function<void(EventLoop*)> func)
{
    epoll_TimeOut_CallBack_ = func;
}

void EventLoop::removeChannel(Channel *ch)        //把channel从红黑树上删除
{
    ep_->removeChannel(ch);
}

//判断当前线程是否为事件循环线程
bool EventLoop::isInLoopThread()  
{
    return threadID_ == syscall(SYS_gettid);
}

//把任务队列添加到队列中
void EventLoop::queueInLoop(std::function<void()> func)
{
    //func();//刺客data指针的生命周期还在
    {
        std::lock_guard<std::mutex> m(mutex_);  //给任务队列加锁
        taskQueue_.push(func);
    }

    //唤醒事件循环
    wakeUp();
    usleep(1);//他妈的的外层函数的指针data栈空间会被释放
}

//用eventfd唤醒事件循环
void EventLoop::wakeUp()
{
    uint64_t val = 1;
    write(wakeupfd_, &val, sizeof(val));
}

//事件循环被唤醒后执行的函数
void EventLoop::handleWakeUp()
{
    // printf("handle wakeUp() threadID is %ld.\n", syscall(SYS_gettid));

    uint64_t val;
    read(wakeupfd_, &val, sizeof(val)); //从eventfd中读取数据，如果不读取，eventfd的读事件会一直触发

    std::function<void()> func;
    std::lock_guard<std::mutex> gd(mutex_);     //给任务队列加锁

    while(taskQueue_.size() > 0)
    {
        func = std::move(taskQueue_.front());
        taskQueue_.pop();
        func();     //执行任务
    }
}

//闹钟响时执行的函数
void EventLoop::handleTimer()
{
    //重新计时
    struct itimerspec timeout;      //定时时间的数据结构
    memset(&timeout, 0, sizeof(struct itimerspec));
    timeout.it_value.tv_sec = timetvl_;    //定时时间,固定为5，方便测试
    timeout.it_value.tv_nsec = 0;   
    timerfd_settime(timerfd_, 0, &timeout, 0);
    if(mainloop_)
    {

    }
    else
    {
        time_t now = time(0);   //获取当前时间

        for (auto it = conns_.begin(); it != conns_.end();) 
        {  
            if (it->second->timeOut(now, timeout_)) 
            {  
                {
                    std::lock_guard<std::mutex> gd(mmutex_);
                    it = conns_.erase(it);      //从EventLoop的map中删除超时的conn
                } 
                timerCallBack_(it->first);  //从TcpServer的map中删除超时的conn
            } 
            else 
            {  
                ++it;
            }  
        }
    }
}     

//把Connection对象保存在conns_中;
void EventLoop::newConnection(spConnection conn)
{
    std::lock_guard<std::mutex> gd(mmutex_);
    conns_[conn->fd()] = conn;
}

//将被设置为TcpServer::removeConn()
void EventLoop::setTimerCallBack(std::function<void(int)> func)
{
    timerCallBack_ = func;
}